import { HttpService } from '@nestjs/axios';
import { Body, Controller, Get, Post, Req } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { lastValueFrom } from 'rxjs';
import { User } from 'src/entities/User';
import { RedisService } from 'src/redis/redis.service';
import { getTime, successReturn } from 'src/utils';
import { XjwtService } from 'src/xjwt/xjwt.service';
import { UserService } from '../user/user.service';

@Controller('login')
export class LoginController {
    constructor(
        private configService:ConfigService,
        private httpService:HttpService,
        private redisService:RedisService,
        private userService:UserService,
        private xjwtService:XjwtService
    ) {}

    @Post()
    async login(@Body('code') code:string, @Req() { IS_WECHANT, IS_ALIPAY}) {
        if(!code || typeof code !== 'string') return

        
        const data =  IS_WECHANT ? await this.wechant(code) : await this.alipay()

        const openid = IS_WECHANT ? data.openid : data.user_id

        const lockKey = 'login:' + openid

        const lock = await this.redisService.store.set(lockKey,'', {NX : true, EX : 10})
        if(!lock) return

        const time = getTime()
        let userId = 0
        const user = await this.userService.user({openid}, ['userId', 'unionid', 'avatar', 'nickname'])
        let userData:{[key in keyof User]? : User[key]} = {}
        if(user) {
            userId = user.userId
            userData.lastLoginTime = time
            if(IS_WECHANT) {
                userData.sessionKey = data.session_key
                if(!user.unionid && data.unionid) {
                    userData.unionid = data.unionid
                }
            }else {
                userData.sessionKey = data.access_token
            }

            const rs = await this.userService.update(userId, userData)
            this.redisService.del(lockKey)
            if(!rs) return null

        }else { //第一次的，注册
            userData.openid = openid
            userData.registerTime = time
            userData.lastLoginTime = time

            if(IS_WECHANT) {
                userData.sessionKey = data.session_key
                if(data.unionid) {
                    userData.unionid = data.unionid
                }
            }else {
                userData.sessionKey = data.access_token
            }

            userId = await this.userService.newUser(userData)
            this.redisService.del(lockKey)
            if(!userId) return null
        }

        return successReturn({
            ...this.makeToken(userId, null, time),
            avatar : user ? user.avatar : '',
            nickname : user ? user.nickname : '',
        })
        
    }

    async wechant(code:string) {
        const wxConfig = this.configService.get('wechat')
        const response = await this.httpService.get(wxConfig.authCode2SessionUrl, {
            timeout : 10000,
            params : {
                js_code : code,
                appid : wxConfig.appid,
                secret : wxConfig.secret
            }
        })

        const { data } = await lastValueFrom(response)

        if(data.errcode) {
            return null
        }

        return data
    }

    async alipay() {
        return {}
    }

    makeToken(userId:number, jwtConfig?:any, time?:number) {
        if(!jwtConfig) {
            jwtConfig = this.configService.get('jwt')
        }

        if(!time) {
            time = getTime()
        }
        
        let accessToken = this.xjwtService.sign({key : userId * jwtConfig.login.scale + jwtConfig.login.scale, id : Math.ceil((time - 1030) / 263), time : time}, {
            secret : jwtConfig.login.secret,
            expiresIn : jwtConfig.expire
        })

        let refreshToken = this.xjwtService.sign({key : userId * jwtConfig.refreshLogin.scale - jwtConfig.refreshLogin.scale, rid : Math.ceil((time - 8030) / 463), time : time}, {
            secret : jwtConfig.refreshLogin.secret,
            expiresIn : jwtConfig.expire
        })



        return {
            accessToken,
            refreshToken,
            expire : jwtConfig.expire
        }

    }
}
